/*
 * Atom.cpp
 *
 *  Created on: 27.07.2012
 *      Author: maikel
 */

#include "Atom.h"
#include <string>
#include <sstream>
#include <limits>

using namespace std;

namespace gro {


/*
 * remove leading and ending whitespace from strings. used with names of atoms
 */
const string trim(const string& pString,
                  const string& pWhitespace = " \t")
{
    const size_t beginStr = pString.find_first_not_of(pWhitespace);
    if (beginStr == string::npos)
    {
        // no content
        return "";
    }

    const size_t endStr = pString.find_last_not_of(pWhitespace);
    const size_t range = endStr - beginStr + 1;

    return pString.substr(beginStr, range);
}


/*
 * if parsing the line fails, the stream position will be set to its original position
 * and the failbit will be set to indicate a logical error.
 */
istream &operator>>(istream &is, Atom &a) {
	const unsigned length_pos      = 4*5 + Atom::dim*8;
	const unsigned length_pos_velo = 4*5 + 2*Atom::dim*8;
	istringstream iss;
	string line;
	streampos start;

	// remember start position
	start = is.tellg();

	getline(is, line);
	if (line.find('\r') != string::npos) {
		line.resize(line.length()-1);
	}

	// check line length, if invalid stop acting and set error flag
	if (line.length() != length_pos && line.length() != length_pos_velo) {
		is.seekg(start);
		is.setstate(ios::failbit);
		return is;
	}
/*
	// read residue number
	iss.str(line.substr(0,5));
	if (!(iss >> a.residue.number)) {
		is.seekg(start);
		is.setstate(ios::failbit);
		return is;
	}

	// read residue name
	a.residue.name = trim(line.substr(5,5));

	// read atom name
	a.name = trim(line.substr(10,5));

	// read atom number
	iss.clear();
	iss.str(line.substr(15,5));
	if (!(iss >> a.number)) {
		is.seekg(start);
		is.setstate(ios::failbit);
		return is;
	}
*/
	// read position coordinates
	double x[3];
	for (int i = 0; i < Atom::dim; i++) {
		iss.clear();
		iss.str(line.substr(20 + i*8, 8));
		if (!(iss >> x[i])) {
			is.seekg(start);
			is.setstate(ios::failbit);
			return is;
		}
	}
	a.position << x[0], x[1], x[2];

	// ignore rest of the line (TODO velocity should be parsed here)

	return is;
}

} /* namespace gro */
